package snippet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Vector;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.L2CAPConnection;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;

public class Cliente
    implements
        DiscoveryListener,
        Runnable
{

    private Object lock;;
    private Vector<RemoteDevice> dDescobertos;
    private String connectionURL;
    private LocalDevice localDevice;
    private DiscoveryAgent dAgente;
    private UUID[] uuidset;
    private BufferedReader bReader;
    private Envelope envelope;
    private Status status;

    public Cliente(
        String uuidgen,
        Envelope envelope,
        Status status )
    {
        lock = new Object();
        dDescobertos = new Vector<RemoteDevice>();
        uuidset = new UUID[ 1 ];
        uuidset[ 0 ] = new UUID( uuidgen, true );
        try {
            localDevice = LocalDevice.getLocalDevice();
        } catch( BluetoothStateException e ) {
            System.out.println( "Cliente: Não foi possivel pegar o dispositivo local" );
        }
        bReader = new BufferedReader( new InputStreamReader( System.in ) );
        this.envelope = envelope;
        this.status = status;
    }

    private void listDevicesFounded()
    {

        dAgente = localDevice.getDiscoveryAgent();
        System.out.println( "Inquiry..." );

        try {
            dAgente.startInquiry( DiscoveryAgent.GIAC, this );
        } catch( BluetoothStateException e ) {
            System.out.println( "Cliente: Inquiry mal sucedida." );
            e.printStackTrace();
        }

        try {
            synchronized( lock ) {
                lock.wait();
            }
        } catch( InterruptedException e ) {
            e.printStackTrace();
        }
        System.out.println( "Cliente: Inquiry completo." );

        printDevices( dDescobertos );

    }

    private void printDevices(
        Vector<RemoteDevice> v )
    {
        int nDispositivos = v.size();
        if( nDispositivos <= 0 )
            System.out.println( "Cliente: Não encontrei" );
        else {
            RemoteDevice rd;
            for( int i = 0; i < nDispositivos; i++ ) {
                rd = v.elementAt( i );
                System.out.println( ( i + 1 ) + " > " + rd.getBluetoothAddress() );
            }
        }
    }

    public L2CAPConnection connectToDevice(
        RemoteDevice rd )
    {
        L2CAPConnection lc = null;
        try {
            System.out.println( "Cliente: Buscando serviços..." );
            dAgente.searchServices( null, uuidset, rd, this );
        } catch( BluetoothStateException e ) {
            System.out.println( "Cliente: Não foi possivel buscar serviços." );
            e.printStackTrace();
        }
        try {
            synchronized( lock ) {
                lock.wait();
            }
        } catch( InterruptedException e ) {
            e.printStackTrace();
        }

        if( connectionURL != null ) {
            try {
                System.out.println( connectionURL );
                lc = (L2CAPConnection) Connector.open( connectionURL );
                envelope.set( rd );
            } catch( IOException e ) {
                System.out.println( "Cliente: problema ao conectar com o servidor." );
                e.printStackTrace();
            }
        }
        return lc;
    }

    private L2CAPConnection getDeviceAndPrepareToConnect()
    {
        int nDispositivos = dDescobertos.size();
        int indiceDoDispositivoNaTela = - 1;
        List<RemoteDevice> vizinhos;
        RemoteDevice rd = null;
        if( nDispositivos <= 0 )
            System.out.println( "Cliente: Não encontrei" );
        else {
            System.out.println( "Cliente: Escolhe dispositivo para pedir a conexão" );
            try {
                indiceDoDispositivoNaTela = Integer.parseInt( bReader.readLine().trim() );
            } catch( NumberFormatException e1 ) {
                System.out.println( "Cliente: Numero fora de formato" + e1 );
            } catch( IOException e1 ) {
                System.out.println( "Cliente: Leitura incorreta" );
            }

            rd = dDescobertos.elementAt( indiceDoDispositivoNaTela - 1 );
            vizinhos = envelope.get();

            if( vizinhos.contains( rd ) ) {
                System.out.println( "Dispositivo já conectado" );
                return null;
            }
        }
        return connectToDevice( rd );
    }

    public void communication()
    {
        int is, os;
        boolean ligado;

        String message = "Token";
        L2CAPConnection conn = getDeviceAndPrepareToConnect();
        try {
            while( true ) {
                ligado = status.getStatus();
                if( ligado == false )
                    break;
                //is = conn.getReceiveMTU();
                //os = conn.getTransmitMTU();
                //byte[] rbuf = new byte[ is ];
                //conn.send( message.getBytes() );
                //conn.receive( rbuf );
                //System.out.println( "Received: " + new String( rbuf ) );
            }
            conn.close();
        } catch( IOException e ) {
            // TODO: handle exception
        }
    }

    @Override
    public void deviceDiscovered(
        RemoteDevice rd,
        DeviceClass dc )
    {
        if( ! dDescobertos.contains( rd ) )
            dDescobertos.add( rd );
    }

    @Override
    public void inquiryCompleted(
        int arg0 )
    {
        synchronized( lock ) {
            lock.notify();
        }
    }

    @Override
    public void serviceSearchCompleted(
        int arg0,
        int arg1 )
    {
        synchronized( lock ) {
            lock.notify();
        }
    }

    @Override
    public void servicesDiscovered(
        int arg0,
        ServiceRecord[] srec )
    {
        if( srec != null && srec.length > 0 )
            connectionURL = srec[ 0 ].getConnectionURL( srec[ 0 ].NOAUTHENTICATE_NOENCRYPT, false )
                + ";ReceiveMTU=512;TransmitMTU=512";
        synchronized( lock ) {
            lock.notify();
        }
    }

    @Override
    public void run()
    {
        // TODO colocar laço
        System.out.println( "Cliente: meu nome é " + localDevice.getFriendlyName() + " endereço "
            + localDevice.getBluetoothAddress() );
        listDevicesFounded();
        communication();
    }
}